
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2008-2011, Salzburg Research. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither the name of the KiWi Project nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Contributor(s):
 * Thomas Kurz
 *
 * File Info:
 * User: Thomas Kurz
 * Date: 2011/02/01
 * Time: 15:55
 *
 * Project: KiWi2, KiWi2 module
 */

/**
 * This widget allows to add, delete and alert configuration properties for kiwi2 core model.
 * The wiget uses jQuery and jQuery ui and is tested for jquery-1.4.4.min.js and jquery-ui-1.8.9.custom
 * in Firefox 3.6.13 and Safari 5.0.2.
 * The widget can be used via jQuery as follows:
 *    $('#content').systemconfig(options);
 * whereby options is a javascript object with value:
 *    host::String = defines the host where the application and the widgets run
 *    lang::"de"|"en"|x = defines the language (de and en are defines, all other languages can be defined via labels object)
 *    labels::object = labels in different languages (for more info have a look at codelines 288ff)
 */
$.kiwi2 = $.kiwi2 || {};
$.widget("kiwi2.systemconfig", {
    /**
     * is called when widget gets initialized
     */
    _init: function(){
        this.initContainer();
        this.initDialog();
        this.writeContent();
    },

    /**
     * build html environment for the widget
     */
    initContainer: function() {
        var that = this;
        var widget = $("<div/>",{"class":"widget ui-widget"});
        this.contentBox = $("<div/>",{"class":"widget-content ui-widget-content"});
        this.contentBox.text(this.options.labels.loading[this.options.lang]);
        var headerBox = $("<div/>",{"class":"widget-header ui-widget-header"});
        var header = $("<h3/>");
        var buttons = $("<div/>",{"style":"float:right;margin-top:-18px;margin-right:2px;"});
        this.blinder = $("<button/>",{"class":"small-button"});
        this.blinder.text(this.options.labels.showhide[this.options.lang])
        this.blinder.button({icons: {primary: "ui-icon-minus"},text:false});
        this.blinder.click(function(){
            that.hideContent();
        });
        buttons.append(this.blinder);
        header.text(this.options.labels.title[this.options.lang]);
        this.element.html("");
        widget.appendTo(this.element);
        headerBox.appendTo(widget);
        this.contentBox.appendTo(widget);
        header.appendTo(headerBox);
        buttons.appendTo(headerBox);
    },

    /**
     * build a html environment for the dialog
     */
    initDialog: function() {
        this.dialog = $("<div style='display:none'/>");
        this.dialog.appendTo(this.element);
    },

    /**
     * opens a dialog, where the user must confirm, if he wants to delete a property or not
     * @param property which should be deleted
     */
    openRemoveDialog: function(property) {
        if(property == "") {
            alert("New property can not be deleted");
            return false;
        }
        var that = this;
        this.dialog.text(this.options.labels.removeContent[this.options.lang]);
        this.dialog.dialog({modal:true,
                            title: this.options.labels.removeTitle[this.options.lang]+" "+property,
                            resizable: false,
                            width: 400,
                            buttons:[{text:this.options.labels.cancel[this.options.lang],click: function() {
                                that.dialog.dialog("close");
                            }},{text:this.options.labels.ok[this.options.lang],click: function() {
                                that.deleteProperty(property);
                            }}]
        });
    },

    /**
     * opens a dialog, where the user must confirm, if he wants to save property(values) or not
     * @param property which should be saved (empty string means create new property)
     * @param values is an array of strings
     */
    openSaveDialog: function(property,values) {
        if(property == "") {
            //get last property
            property = $('input',$('td',$('tr',this.contentBox).last()).first()).val();
        }
        var that = this;
        this.dialog.text(this.options.labels.saveContent[this.options.lang]);
        this.dialog.dialog({modal:true,
                            title: this.options.labels.saveTitle[this.options.lang]+" "+property,
                            resizable: false,
                            width: 400,
                            buttons:[{text:this.options.labels.cancel[this.options.lang],click: function() {
                                that.dialog.dialog("close");
                            }},{text:this.options.labels.ok[this.options.lang],click: function() {
                                that.saveValues(property,values);
                            }}]
        });
    },

    /**
     * send a POST to the configuration webservice (url is 'host'/core/config/data/'property')
     * @param property which should be saved
     * @param values is a list of values that should be saved
     */
    saveValues: function(property,values) {
        var that = this;

        /**
         * build an json array string out of a javascript string array
         * @param data is a javascript string array
         */
        var toJsonArrayString = function(data) {
            var s = "[";
            for(var i=0; i < data.length; i++) {
                s += '"'+data[i]+'"';
                if(i != data.length-1) {
                    s +=",";
                }
            }
            return s+"]";
        };
        var data = toJsonArrayString(values);

        /**
         * send the HTTP POST with values:
         * success: -> if false is returned, do alert & close dialog
         * error: -> do alert & close dialog
         */
        $.ajax({
            type:"POST",
            contentType: "application/json",
            url: this.options.host+"/core/config/data/"+property,
            data: data,
            success: function(result) {
                if(!result) alert("Could not save values: internal error.")
                that.closeDialog();
            },
            error: function(jXHR) {
                alert(jXHR.statusText);
                that.closeDialog();
            }
        });
    },

    /**
     * send a DELETE to the configuration webservice (url is 'host'/core/config/data/'property')
     * @param property which should be deleted
     */
    deleteProperty: function(property) {
        var that = this;

        /**
         * send the HTTP DELETE:
         * success: -> if false is returned, do alert & close dialog
         * error: -> do alert & close dialog
         */
        $.ajax({
            type:"DELETE",
            url: this.options.host+"/core/config/data/"+property,
            success: function(result) {
                if(!result) alert("Could not delete property: internal error.")
                that.closeDialog();
            },
            error: function(jXHR) {
                alert(jXHR.statusText);
                that.closeDialog();
            }
        });
    },

    /**
     * closes the dialog and re-renders content
     */
    closeDialog: function() {
        this.contentBox.text(this.options.labels.loading[this.options.lang])
        this.dialog.dialog("close");
        this.writeContent();
    },

    /**
     * get all properties and values and show them in a list, show also buttons for change operations
     */
    writeContent: function() {
        var table = $("<table style='border:1px solid #d3d3d3;border-top:none;' cellspacing='0'/>");
        var that = this;

        /**
         * get the data a json list from configuration webservice (url = 'host'/core/config/list)
         */
        $.get(this.options.host+"/core/config/list",function(data){
            //delete loading

            //sort list and write table rows
            that.contentBox.html(table);
            var sorted = [];
            for (property in data) {
               sorted.push(property);
            }
            sorted.sort();
            for(var i=0; i<sorted.length; i++) {
                buildRow(sorted[i],data).appendTo(table);
            }
            //append empty name value pair
            buildRow("","").appendTo(table);
        });

        /**
         * build a single row for a given property
         * @param property
         * @param data
         */
        var buildRow = function(property,data) {
            var tr = $("<tr/>");
            var name = $("<td style='border-top:1px solid #d3d3d3;padding-top:8px;padding-left:5px;font-weight:bold' valign='top'/>");
            var value = $("<td style='border-top:1px solid #d3d3d3;'/>");
            var buttons = $("<td style='border-top:1px solid #d3d3d3;' valign='bottom'/>");

            /**
             * build a button, that delets either a single value or (if there is just one value) the whole property
             * @param div which includes input field and button
             * @param td which includes all input fields
             * @param property
             */
            var buildDelButton = function(div,td,property) {
                var del = $("<button/>").click(function(){
                    //test if there are more input fields
                    if($("input",td).size() == 1) {
                        that.openRemoveDialog(property);
                    } else {
                        div.remove();
                    }
                });

                del.text(that.options.labels.delete_value[that.options.lang]);
                del.button({icons: {primary: "ui-icon-close"},text: false});
                div.append(del);
            }

            /**
             * append input field and delete button on the table desk
             * @param td
             * @param value
             */
            var buildValue = function(td,value) {
                var div = $("<div/>");
                var input = $("<input  style='margin-right:5px;margin-left:10px' type='text' size='60' value='" + value + "'>");
                div.append(input);
                buildDelButton(div,td,property);
                td.append(div);
            };

            /**
             * build save and add button for a single property
             * @param values
             * @param td
             * @param property
             */
            var buildButtons = function(values,td,property) {
                var set = $("<button/>").click(function(){
                    var v = [];
                    $("input",values).each(function(){
                        v.push($(this).val())
                    });
                    that.openSaveDialog(property,v);
                });
                set.text(that.options.labels.save_property[that.options.lang]);
                set.button({icons: {primary: "ui-icon-check"},text:false});

                var add = $("<button/>").click(function(){
                    buildValue(value,"");
                });
                add.text(that.options.labels.add_value[that.options.lang]);
                add.button({icons: {primary: "ui-icon-plus"},text:false});

                var buttons = $("<div/>");
                buttons.append(add);
                buttons.append(set);
                buttons.buttonset();
                buttons.appendTo(td);

            };

            //build value rows for properties (single row or a whole bunch)
            if (data[property] instanceof Array && data[property].length > 0) {
                //list of values for one name
                name.text(property);
                for (var i = 0; i < data[property].length; i++) {
                    buildValue(value,data[property][i]);
                }
            } else {
                if(property == "") {
                    name.css({'padding-top':'3px','font-weight':'normal'});
                    var input = ("<input type='text' size='40' value=''/>")
                    name.append(input);
                    buildValue(value,"");
                } else {
                    name.text(property);
                    buildValue(value,data[property]);
                }
            }
            //apend the tds on the tr
            buildButtons(value,buttons,property);
            name.appendTo(tr);
            value.appendTo(tr);
            buttons.appendTo(tr);
            return tr;
        };
    },

    /**
     * if widget is hidden, then show it and vice versa
     */
    hideContent: function() {
        var that = this;
        if(this.contentBox.is(":visible")) {
            this.contentBox.hide("blind",function(){
                that.blinder.button({icons: {primary:"ui-icon-plus"}});
            });
        }
        else {
            this.contentBox.show("blind",function(){
                that.blinder.button({icons: {primary:"ui-icon-minus"}});
            })
        }
    },

    /**
     * this are the options that customize the widget
     */
    options: {
	    host: 'http://localhost:8080/KiWi2',
        labels: {"title":{"de":"System-Konfiguration","en":"System Configuration"},
                 "loading":{"de":"Laden...","en":"Loading..."},
                 "save_property":{"de":"Feldwerte speichern","en":"Save values"},
                 "add_value":{"de":"Wert hinzufügen","en":"Add value"},
                 "delete_value":{"de":"Wert löschen","en":"Delete value"},
                 "removeTitle":{"de":"Feld löschen:","en":"Delete property:"},
                 "removeContent":{"de":"Soll das Feld wirklich gelöscht werden?","en":"Do you want to delete this property"},
                 "saveTitle":{"de":"Feld speichern:","en":"Save property:"},
                 "saveContent":{"de":"Sollen die Änderungen wirklich gespeichert werden?","en":"Do you want save changings?"},
                 "ok":{"de":"OK","en":"OK"},
                 "cancel":{"de":"Abbrechen","en":"Cancel"},
                 "showhide":{"de":"Aus-/Einblenden","en":"Show/Hide"}},
        lang: "de"
    }
});